package cn.ekuma.odbo.mobile.paging

import androidx.lifecycle.asLiveData
import androidx.paging.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow

/**
 * @author : leo
 * @date : 2020/11/10
 * @description : 简易数据分页
 */
class SimplePager<K : Any, V : Any>(
    private val scope: CoroutineScope,
    private val pageSize: Int = 20,
    private val initialLoadSize: Int = pageSize,
    private val prefetchDistance: Int = pageSize,
    private val maxSize: Int = PagingConfig.MAX_SIZE_UNBOUNDED,
    private val enablePlaceholders: Boolean = false,
    private val initialKey: K? = null,
    private val pagingSource: () -> PagingSource<K, V>? = { null },
    private val loadData:
    suspend (PagingSource.LoadParams<K>) -> PagingSource.LoadResult<K, V>? = { null }
) {

    fun getData(): Flow<PagingData<V>> {
        return Pager(
            PagingConfig(
                pageSize,
                initialLoadSize = initialLoadSize,
                prefetchDistance = prefetchDistance,
                maxSize = maxSize,
                enablePlaceholders = enablePlaceholders
            ),
            initialKey = initialKey
        ) {
            pagingSource() ?: object : PagingSource<K, V>() {
                override suspend fun load(params: LoadParams<K>): LoadResult<K, V> {
                    return loadData(params) ?: throw IllegalArgumentException(
                        "one of pagingSource or loadData must not null"
                    )
                }

                override fun getRefreshKey(state: PagingState<K, V>): K? {
                    return initialKey
                }
            }
        }.flow.cachedIn(scope)
    }

    fun getScope() = scope
}

/**
 * Created by ve3344@qq.com.
 */
/**
 * 通用加载器
 */
typealias PageLoader<I> = suspend (pageIndex: Int, loadSize: Int, reachedEnd: () -> Unit) -> List<I>
/**
 * 通用分页加载
 */
fun <T : Any> pageData(
    pagingConfig: PagingConfig = PagingConfig(pageSize = 4),
    loader: PageLoader<T>
) =
    Pager(pagingConfig) { SimplePagingSource(loader) }
        .flow
        .asLiveData()
/**
 * 通用带缓存分页加载
 */
fun <T : Any> pageDataWithCache(
    scope: CoroutineScope,
    pagingConfig: PagingConfig = PagingConfig(pageSize = 4),
    loader: PageLoader<T>
) =
    Pager(pagingConfig) { SimplePagingSource(loader) }
        .flow
        .cachedIn(scope)
        .asLiveData()

/**
 * 通用pa
 */
open class SimplePagingSource<I : Any>(
    private val load: PageLoader<I>,
    private val initialKey: Int = 1
) :
    PagingSource<Int, I>() {
    override suspend fun load(params: LoadParams<Int>): LoadResult<Int, I> {
        return try {
            val nextPage = params.key ?: initialKey
            var hasMore=true
            val response = load(nextPage, params.loadSize){
                hasMore=false
            }
            LoadResult.Page(
                data = response,
                prevKey = if (nextPage == initialKey) null else nextPage - 1,
                nextKey = if (hasMore) nextPage + 1 else null
            )
        } catch (e: Exception) {
            LoadResult.Error(e)
        }
    }

    override fun getRefreshKey(state: PagingState<Int, I>): Int? = null
}